<?php

abstract class ME_Abstract_Pdo extends ME_Abstract_DBOlder
{
	protected $db;
	protected $master;
	protected $slave;
	protected $forceReadMaster = false;
	protected $username = 'root';
	protected $password;
	protected $engine = 'mysql';
	protected $sqlComment = '';
	protected static $instance = array();

	public function __construct()
	{
		if (!empty($this->servers['engine']))
		{
			$this->engine = $this->servers['engine'];
		}
		if (defined('DB_USERNAME'))
		{
			$this->username = DB_USERNAME;
		}
		if (defined('DB_PASSWORD'))
		{
			$this->password = DB_PASSWORD;
		}
		if (!empty($this->servers['username']))
		{
			$this->username = $this->servers['username'];
		}
		if (!empty($this->servers['password']))
		{
			$this->password = $this->servers['password'];
		}                
		$masterDns = $this->engine . ':dbname=' . $this->servers['master']['database'] .
			';host=' . $this->servers['master']['host'];   
		try {
			$this->master = new PDO( $masterDns, $this->username,
				$this->password);
		} catch (PDOException $e)
		{
			trigger_error($e->getMessage(), E_USER_WARNING);
			//throw new ME_Exception($e->getMessage());
			return false;
		}
		if (!empty($this->servers['slave']))
		{
			$slaveDns = $this->engine . ':dbname=' . $this->servers['slave']['database'] .
				';host=' . $this->servers['slave']['host']; 
			try {
				$this->slave = new PDO( $slaveDns, $this->username, 
					$this->password, array(PDO::ATTR_PERSISTENT => true));
			} catch (PDOException $e) {
				trigger_error($e->getMessage(), E_USER_WARNING);
			}
		}
		$this->db =& $this->master;
		if (empty($this->db))
		{
			if (!empty($this->slave))
			{
				$this->db =& $this->slave;
			}
			else 
			{
				trigger_error('No any instance of DB!', E_USER_WARNING); 

				return false;
			}
		}
	   // echo "这个是：".$_SERVER['HOSTNAME'];
		$this->sqlComment = empty($_SERVER['REQUEST_METHOD'])? ( '/* ' . addslashes( strtr( $_SERVER['HOSTNAME'] . $_SERVER['SCRIPT_FILENAME'], '*', '#' ) ) . ' */' ): ( '/* ' . addslashes( strtr( $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'], '*', '#' ) )  . ' */' );

		return true;
	}

	public static function instance($dbName = null)
	{
		if ($dbName === null)
		{
			$dbName = get_called_class();
		}
		if (empty($dbName))
		{    
			return false;
		}
		if (substr($dbName, 0, 2) != 'Db')
		{
			return false;
		}
		if (!isset(self::$instance[$dbName]))
		{
			self::$instance[$dbName] = new $dbName;
                        self::$instance[$dbName]->query("set names utf8");
			self::$instance[$dbName]->query('set session wait_timeout=3600');
		}
	   
		return self::$instance[$dbName];
	}
	
	public function forceReadMaster()
	{
		$this->forceReadMaster = true;

		return $this;
	}    
	
	protected function chooseDbConn($sql)
	{
		if (empty($sql))
		{
			return false;
		}
		if ($this->db !== $this->master)
		{
			$this->db =& $this->master;
		}
		if ('SELECT' == strtoupper(strtok($sql, ' ')) && false == $this->forceReadMaster)
		{
			if (!empty($this->slave))
			{
				$this->db =& $this->slave;
			}
			else
			{
				trigger_error('Server is using master server to operate, because of that the slave server does not exist.'
				   , E_USER_WARNING);
			}   
		}
		elseif (empty($this->master))
		{
			throw new ME_Exception('Dose not exist instance of DB of master server!');
		}
		return true;
	}

	public function query($sql = '')
	{
		$this->chooseDbConn($sql);
		$sql .= $this->sqlComment;
		$query = $this->db->query($sql);
		if (empty($query))
		{
			$error = $this->errorInfo();
			trigger_error($error[2], E_USER_WARNING);
		}
		if (!empty($this->forceReadMaster))
		{
			$this->forceReadMaster = false;
		}
		return $query;
	}

	public function getOne($sql)
	{
		$query = $this->query($sql);

		return ($query instanceof PDOStatement) ? $query->fetchColumn() : null;
	}

	public function getRow($sql, $fetchStyle = PDO::FETCH_ASSOC)
	{
		$query = $this->query($sql);
		$row = ($query instanceof PDOStatement) ? $query->fetch($fetchStyle) : null;

		return $row;
	}

	public function getAll($sql, $fetchStyle = PDO::FETCH_ASSOC)
	{
		$query = $this->query($sql);
		$result = ($query instanceof PDOStatement) ? $query->fetchAll($fetchStyle) : null;

		return $result;
	}

	public function beginTransaction()
	{
		return ($this->master instanceof PDO) ? $this->master->beginTransaction() : false;
	}

	public function commit()
	{
		return ($this->master instanceof PDO) ? $this->master->commit() : false;
	}

	public function errorCode()
	{
		return ($this->db instanceof PDO) ? $this->db->errorCode() : false;
	}

	public function errorInfo()
	{
		return ($this->db instanceof PDO) ? $this->db->errorInfo() : false;
	}

	public function exec($statement = '')
	{
		$this->chooseDbConn($statement);
		$ret = ($this->db instanceof PDO) ? $this->db->exec($statement) : false;
		$this->forceReadMaster = false;

		return $ret;
	}

	public function lastInsertId()
	{
		return ($this->master instanceof PDO) ? $this->master->lastInsertId() : false;
	}

	public function prepare($statement = '', array $options = array())
	{
		$this->chooseDbConn($statement);
		$ret = ($this->db instanceof PDO) ? $this->db->prepare($statement, $options) : false;
		if (true == $this->forceReadMaster)
		{
			$this->forceReadMaster = false;
		}

		return $ret;
	}

	public function quote($string, $parameterType = PDO::PARAM_STR)
	{
		return ($this->db instanceof PDO) ? $this->db->quote($string, $parameterType) : false;
	}

	public function rollBack()
	{
		return ($this->master instanceof PDO) ? $this->master->rollBack() : false;
	}

	public function setAttribute($attribute, $value)
	{
		return ($this->db instanceof PDO) ? $this->db->setAttribute($attribute, $value) : false;
	}

	public function getAvailableDrivers()
	{
		return ($this->db instanceof PDO) ? $this->db->getAvailableDrivers() : false;
	}

	public function getAttribute($attribute)
	{
		return ($this->db instanceof PDO) ? $this->db->getAttribute($attribute) : false;
	}
}

?>
